package cz.proks.easyhelpdesk.gwt.ui.widget;

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.google.gwt.cell.client.ButtonCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.NumberCell;
import com.google.gwt.cell.client.SelectionCell;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.SingleSelectionModel;

import cz.proks.easyhelpdesk.api.model.Helpdesk;
import cz.proks.easyhelpdesk.api.model.HelpdeskRole;
import cz.proks.easyhelpdesk.api.model.User;
import cz.proks.easyhelpdesk.gwt.HelpdeskMessages;
import cz.proks.easyhelpdesk.gwt.event.HasMemberAddToHelpdeskHandlers;
import cz.proks.easyhelpdesk.gwt.event.HasMemberDeleteFromHelpdeskHandlers;
import cz.proks.easyhelpdesk.gwt.event.HasRoleChangeHandlers;
import cz.proks.easyhelpdesk.gwt.event.MemberAddToHelpdeskEvent;
import cz.proks.easyhelpdesk.gwt.event.MemberDeleteFromHelpdeskEvent;
import cz.proks.easyhelpdesk.gwt.event.MemberDeleteFromHelpdeskEvent.Handler;
import cz.proks.easyhelpdesk.gwt.event.RoleChangeEvent;
import cz.proks.easyhelpdesk.gwt.keyprovider.KeyProvider;
import cz.proks.easyhelpdesk.gwt.ui.cell.CellWithRights;
import cz.proks.easyhelpdesk.gwt.ui.cell.EmptyTextCell;

public class MembersSettingsWidget extends Composite implements RequiresErase, HasMemberAddToHelpdeskHandlers, HasMemberDeleteFromHelpdeskHandlers, HasRoleChangeHandlers {

    private static MembersSettingsWidgetUiBinder uiBinder = GWT.create(MembersSettingsWidgetUiBinder.class);
    
    interface MembersSettingsWidgetUiBinder extends UiBinder<Widget, MembersSettingsWidget> {
    }        
    
    private final static int ID_COLUMN = 0;
    private final static int NAME_COLUMN = 1;
    private final static int EMAIL_COLUMN = 2;
    private final static int HELPDESK_ROLES_COLUMN = 3;
    private final static int DELETE_COLUMN = 4;
     
    private final KeyProvider<User> keyProvider = new KeyProvider<User>();
    private final ListDataProvider<User> dataProvider = new ListDataProvider<User>(keyProvider);
    
    @UiField HelpdeskMessages i18n;
    @UiField(provided=true) CellTable<User> membersTable = new CellTable<User>(keyProvider);    
    @UiField TextBox newUserIdBox;
    @UiField ListBox newUserRoleBox;
    @UiField RedButton newUserSaveButton;
        
    private Helpdesk helpdesk;
    
    private final Collection<HelpdeskRole> helpdeskRoles = new LinkedList<HelpdeskRole>();
    private final Map<User, HelpdeskRole> membersRoles = new HashMap<User, HelpdeskRole>();
    private final Map<User, Boolean> membersRights = new HashMap<User, Boolean>(); 

    public MembersSettingsWidget() {
        initWidget(uiBinder.createAndBindUi(this));        
    }
    
    @Override
    protected void initWidget(Widget widget) {     
        initTable();
        
        super.initWidget(widget);   
        
    }    
    
    @Override
    public HandlerRegistration addMemberAddToHelpdeskHandler(cz.proks.easyhelpdesk.gwt.event.MemberAddToHelpdeskEvent.Handler handler) {
        return addHandler(handler, MemberAddToHelpdeskEvent.TYPE);
    }
    
    @Override
    public HandlerRegistration addMemberDeleteFromHelpdeskHandler(Handler handler) {
        return addHandler(handler, MemberDeleteFromHelpdeskEvent.TYPE);
    }
    
    @Override
    public HandlerRegistration addRoleChangeHandler(cz.proks.easyhelpdesk.gwt.event.RoleChangeEvent.Handler handler) {
        return addHandler(handler, RoleChangeEvent.TYPE);
    }
    
    @Override
    public void onErase() {
        newUserIdBox.setText("");
        newUserRoleBox.setSelectedIndex(newUserRoleBox.getItemCount() > 0 ? 0 : -1);
    }
    
    public void setHelpdesk(Helpdesk helpdesk) {
        this.helpdesk = helpdesk;
    }        

    public List<User> getEntities() {
        return dataProvider.getList();
    }
    
    public Long getNewUserId() {
        return Long.valueOf(newUserIdBox.getText());
    }
    
    public void setNewUserId(Long userId) {
        this.newUserIdBox.setText(userId == null ? "" : String.valueOf(userId));
    }
    
    public HelpdeskRole getSelectedRole() {
        int selected = newUserRoleBox.getSelectedIndex();
        return HelpdeskRole.valueOf(newUserRoleBox.getValue(selected));
    }
        
    public void setHelpdeskRoles(Collection<HelpdeskRole> helpdeskRoles) {
        this.helpdeskRoles.clear();
        this.newUserRoleBox.clear();
        
        if (helpdeskRoles != null) {
            this.helpdeskRoles.addAll(helpdeskRoles);
            
            for (HelpdeskRole role : helpdeskRoles)
                newUserRoleBox.addItem(role.toString(), role.toString());
            
            newUserRoleBox.setSelectedIndex(0);
        }            
        
        refreshTableHelpdeskRolesColumn(true);
    }
    
    public void setMembersRoles(Map<User, HelpdeskRole> membersRoles) {
        this.membersRoles.clear();
        
        if (membersRoles != null)
            this.membersRoles.putAll(membersRoles);
    }
    
    public void setMembers(Map<User, Boolean> members) {
        this.membersRights.clear();
        if (members != null)
            this.membersRights.putAll(members);
        
        getEntities().clear();
        getEntities().addAll(membersRights.keySet());
        
        refreshTableHelpdeskRolesColumn(false);
        refreshTableDeleteColumn(true);
    }
    
    private void initTable() {        
        membersTable.setWidth("100%");
        
        final SingleSelectionModel<User> selection = new SingleSelectionModel<User>(keyProvider);
        
        membersTable.setSelectionModel(selection);
        dataProvider.addDataDisplay(membersTable);
        
        initTableColumns();
    }
    
    private void initTableColumns() {
        Column<User, Number> idColumn = new Column<User, Number>(new NumberCell()) {
            @Override
            public Number getValue(User object) {
                return object.getId();
            }
        };
        
        Column<User, String> nameColumn = new Column<User, String>(new TextCell()) {
            
            @Override
            public String getValue(User object) {
                return object.getName() + " " + object.getSurname();
            }
        };
        
        Column<User, String> emailColumn = new Column<User, String>(new TextCell()) {
            @Override
            public String getValue(User object) {
                return object.getEmail();
            }
        };
                  
        Column<User, String> rolesColumn = getHelpdeskRoleSelectionColumn();                      
        
        Column<User, String> deleteColumn = getDeleteColumn();
        
        membersTable.addColumn(idColumn, i18n.settingsMemberIdColumn());
        membersTable.addColumn(nameColumn, i18n.settingsMemberNameColumn());
        membersTable.addColumn(emailColumn, i18n.settingsMemberEmailColumn());
        membersTable.addColumn(rolesColumn, i18n.settingsMemberRoleColumn());
        membersTable.addColumn(deleteColumn, i18n.settingsMemberDeleteColumn());                
    }
    
    private void refreshTableHelpdeskRolesColumn(boolean flush) {
        membersTable.removeColumn(HELPDESK_ROLES_COLUMN);
        membersTable.insertColumn(HELPDESK_ROLES_COLUMN, getHelpdeskRoleSelectionColumn(), i18n.settingsMemberRoleColumn());
                
        if (flush)
            membersTable.flush();
    }
    
    private void refreshTableDeleteColumn(boolean flush) {
        membersTable.removeColumn(DELETE_COLUMN);
        membersTable.insertColumn(DELETE_COLUMN, getDeleteColumn(), i18n.settingsDelete());
                
        if (flush)
            membersTable.flush();
    }
    
    private Column<User, String> getHelpdeskRoleSelectionColumn() {                    
        CellWithRights<String> rolesCell = new CellWithRights<String>(getColumnRightMap(), new SelectionCell(getHelpdeskRolesLabels()), new TextCell());        
        Column<User, String> rolesColumn = new Column<User, String>(rolesCell) {
            
            @Override
            public String getValue(User object) {        
                return membersRoles.get(object).toString();                                               
            }
        };
        
        rolesColumn.setFieldUpdater(new FieldUpdater<User, String>() {
            
            @Override
            public void update(int index, User object, String value) {
                RoleChangeEvent.fireEvent(MembersSettingsWidget.this, object, HelpdeskRole.valueOf(value));
            }
        });
        
        return rolesColumn;
    }
    
    private Column<User, String> getDeleteColumn() {
        CellWithRights<String> deleteCell = new CellWithRights<String>(getColumnRightMap(), new ButtonCell(), new EmptyTextCell());
        Column<User, String> deleteColumn = new Column<User, String>(deleteCell) {
            @Override
            public String getValue(User object) {
                return i18n.settingsDelete();
            }                        
        }; 
        
        deleteColumn.setFieldUpdater(new FieldUpdater<User, String>() {
            @Override
            public void update(int index, User object, String value) {
                MemberDeleteFromHelpdeskEvent.fireEvent(MembersSettingsWidget.this, helpdesk, object);
            }
        });
        
        return deleteColumn;
    }
    
    
    private Map<Long, Boolean> getColumnRightMap() {
        Map<Long, Boolean> columnRights = new HashMap<Long, Boolean>();
        
        int index = 1; // first row is header
        for (User user : getEntities())
            columnRights.put(user.getId(), membersRights.get(user));
        
        return columnRights;
    }
    
    private List<String> getHelpdeskRolesLabels() {
        List<String> list = new LinkedList<String>();
        
        for (HelpdeskRole role : helpdeskRoles)
            list.add(role.toString());
        
        return list;
    }
    
    private User getMember() {
        User user = new User();
        
        user.setId(getNewUserId());
        
        return user;
    }      

    @UiHandler("newUserSaveButton")
    void onNewUserSaveButtonClick(ClickEvent event) {
        event.preventDefault();
        MemberAddToHelpdeskEvent.fireEvent(this, helpdesk, getMember(), getSelectedRole());        
    }
}